Next.js middleware'ini kullanarak gelişmiş istek değiştirme tekniklerini keşfedin. Güçlü web uygulamaları için karmaşık yönlendirme, kimlik doğrulama, A/B testi ve yerelleştirme stratejilerini öğrenin.
Next.js Middleware Kenar Durumları: İstek Değiştirme Desenlerinde Ustalık
Next.js middleware, isteklerin uygulamanızın rotalarına ulaşmadan önce yakalanması ve değiştirilmesi için güçlü bir mekanizma sağlar. Bu yetenek, basit kimlik doğrulama kontrollerinden karmaşık A/B testi senaryolarına ve uluslararasılaştırma stratejilerine kadar geniş bir olasılık yelpazesi açar. Ancak, middleware'den etkili bir şekilde yararlanmak, onun kenar durumlarını ve potansiyel tuzaklarını derinlemesine anlamayı gerektirir. Bu kapsamlı kılavuz, gelişmiş istek değiştirme desenlerini araştırır, sağlam ve performanslı Next.js uygulamaları oluşturmanıza yardımcı olmak için pratik örnekler ve uygulanabilir içgörüler sağlar.
Next.js Middleware'in Temellerini Anlamak
Gelişmiş desenlere dalmadan önce, Next.js middleware'in temellerini özetleyelim. Middleware fonksiyonları, bir istek tamamlanmadan önce yürütülür ve şunları yapmanızı sağlar:
- URL'leri Yeniden Yazma: Kullanıcıları belirli kriterlere göre farklı sayfalara yönlendirin.
- Kullanıcıları Yönlendirme: Kullanıcıları, genellikle kimlik doğrulama veya yetkilendirme amaçları için tamamen farklı URL'lere gönderin.
- Başlıkları Değiştirme: HTTP başlıkları ekleyin, kaldırın veya güncelleyin.
- Doğrudan Yanıt Verme: Next.js rotalarını atlayarak doğrudan middleware'den bir yanıt döndürün.
Middleware fonksiyonları, /pages
veya /app
dizininizde (Next.js sürümünüze ve kurulumunuza bağlı olarak) middleware.js
veya middleware.ts
dosyasında bulunur. Gelen isteği temsil eden bir NextRequest
nesnesi alırlar ve sonraki davranışı kontrol etmek için bir NextResponse
nesnesi döndürebilirler.
Örnek: Temel Kimlik Doğrulama Middleware'i
Bu örnek, basit bir kimlik doğrulama kontrolü göstermektedir. Kullanıcı kimliği doğrulanmamışsa (örneğin, bir çerezde geçerli bir belirteç yoksa), oturum açma sayfasına yönlendirilir.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const authToken = request.cookies.get('authToken')
if (!authToken) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/protected/:path*'],
}
Bu middleware yalnızca /protected/:path*
ile eşleşen rotalar için çalışacaktır. Bir authToken
çerezinin varlığını kontrol eder. Çerez eksikse, kullanıcı /login
sayfasına yönlendirilir. Aksi takdirde, istek NextResponse.next()
kullanılarak normal şekilde devam etmesine izin verilir.
Gelişmiş İstek Değiştirme Desenleri
Şimdi, Next.js middleware'in gerçek gücünü sergileyen bazı gelişmiş istek değiştirme desenlerini keşfedelim.
1. Çerezlerle A/B Testi
A/B testi, kullanıcı deneyimlerini optimize etmek için çok önemli bir tekniktir. Middleware, kullanıcıları uygulamanızın farklı varyasyonlarına rastgele atamak ve davranışlarını izlemek için kullanılabilir. Bu desen, kullanıcının atanmış varyantını korumak için çerezlere dayanır.
Örnek: Bir Açılış Sayfasını A/B Testi Yapmak
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const VARIANT_A = 'variantA'
const VARIANT_B = 'variantB'
export function middleware(request: NextRequest) {
let variant = request.cookies.get('variant')?.value
if (!variant) {
// Bir varyantı rastgele atayın
variant = Math.random() < 0.5 ? VARIANT_A : VARIANT_B
const response = NextResponse.next()
response.cookies.set('variant', variant)
return response
}
if (variant === VARIANT_A) {
return NextResponse.rewrite(new URL('/variant-a', request.url))
} else if (variant === VARIANT_B) {
return NextResponse.rewrite(new URL('/variant-b', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/'],
}
Bu örnekte, bir kullanıcı ilk kez kök yolu (/
) ziyaret ettiğinde, middleware onları rastgele variantA
veya variantB
'ye atar. Bu varyant bir çerezde saklanır. Aynı kullanıcının sonraki istekleri, atanmış varyantlarına bağlı olarak ya /variant-a
ya da /variant-b
'ye yeniden yazılacaktır. Bu, farklı açılış sayfaları sunmanıza ve hangisinin daha iyi performans gösterdiğini izlemenize olanak tanır. Next.js uygulamanızda /variant-a
ve /variant-b
için rotalar tanımladığınızdan emin olun.
Küresel Hususlar: A/B testi yaparken, bölgesel varyasyonları göz önünde bulundurun. Kuzey Amerika'da yankı uyandıran bir tasarım, Asya'da aynı derecede etkili olmayabilir. A/B testini belirli bölgelere uyarlamak için coğrafi konum verilerini (IP adresi araması veya kullanıcı tercihleri aracılığıyla elde edilen) kullanabilirsiniz.
2. URL Yeniden Yazma ile Yerelleştirme (i18n)
Uluslararasılaştırma (i18n), küresel bir kitleye ulaşmak için gereklidir. Middleware, kullanıcının tercih ettiği dili otomatik olarak algılamak ve onları sitenizin uygun yerelleştirilmiş sürümüne yönlendirmek için kullanılabilir.
Örnek: Accept-Language
Başlığına Göre Yönlendirme
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const SUPPORTED_LANGUAGES = ['en', 'fr', 'es', 'de']
const DEFAULT_LANGUAGE = 'en'
function getPreferredLanguage(request: NextRequest): string {
const acceptLanguage = request.headers.get('accept-language')
if (!acceptLanguage) {
return DEFAULT_LANGUAGE
}
const languages = acceptLanguage.split(',').map((lang) => lang.split(';')[0].trim())
for (const lang of languages) {
if (SUPPORTED_LANGUAGES.includes(lang)) {
return lang
}
}
return DEFAULT_LANGUAGE
}
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname
// Pathname'de mevcut bir yerel ayar olup olmadığını kontrol edin
if (
SUPPORTED_LANGUAGES.some(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
)
) {
return NextResponse.next()
}
const preferredLanguage = getPreferredLanguage(request)
return NextResponse.redirect(
new URL(`/${preferredLanguage}${pathname}`, request.url)
)
}
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico).*)'
],
}
Bu middleware, istekten Accept-Language
başlığını çıkarır ve kullanıcının tercih ettiği dili belirler. URL zaten bir dil öneki (örneğin, /en/about
) içermiyorsa, middleware kullanıcıyı uygun yerelleştirilmiş URL'ye (örneğin, Fransızca için /fr/about
) yönlendirir. Farklı yerel ayarlar için `/pages` veya `/app` dizininizde uygun klasör yapısına sahip olduğunuzdan emin olun. Örneğin, bir `/pages/en/about.js` ve bir `/pages/fr/about.js` dosyasına ihtiyacınız olacaktır.
Küresel Hususlar: i18n uygulamanızın sağdan-sola dillere (örneğin, Arapça, İbranice) doğru şekilde işlem yaptığından emin olun. Ayrıca, performansı artırarak, yerelleştirilmiş varlıkları kullanıcılarınıza daha yakın sunuculardan sunmak için bir İçerik Dağıtım Ağı (CDN) kullanmayı düşünün.
3. Özellik Bayrakları
Özellik bayrakları, yeni kod dağıtmadan uygulamanızdaki özellikleri etkinleştirmenize veya devre dışı bırakmanıza olanak tanır. Bu, yeni özellikleri kademeli olarak kullanıma almak veya üretimde özellikleri test etmek için özellikle kullanışlıdır. Middleware, bir özellik bayrağının durumunu kontrol etmek ve isteği buna göre değiştirmek için kullanılabilir.
Örnek: Bir Beta Özelliğini Etkinleştirme
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const BETA_FEATURE_ENABLED = process.env.BETA_FEATURE_ENABLED === 'true'
export function middleware(request: NextRequest) {
if (BETA_FEATURE_ENABLED && request.nextUrl.pathname.startsWith('/new-feature')) {
return NextResponse.next()
}
// İsteğe bağlı olarak bir "özellik kullanılamıyor" sayfasına yönlendirin
return NextResponse.rewrite(new URL('/feature-unavailable', request.url))
}
export const config = {
matcher: ['/new-feature/:path*'],
}
Bu middleware, BETA_FEATURE_ENABLED
ortam değişkeninin değerini kontrol eder. true
olarak ayarlanmışsa ve kullanıcı /new-feature
altında bir rotaya erişmeye çalışıyorsa, isteğin devam etmesine izin verilir. Aksi takdirde, kullanıcı bir /feature-unavailable
sayfasına yönlendirilir. Farklı ortamlar (geliştirme, hazırlık, üretim) için ortam değişkenlerini uygun şekilde yapılandırmayı unutmayın.
Küresel Hususlar: Özellik bayrakları kullanırken, tüm bölgelerdeki düzenlemelere uymayan özellikleri etkinleştirmenin yasal sonuçlarını göz önünde bulundurun. Örneğin, veri gizliliği ile ilgili özelliklerin bazı ülkelerde devre dışı bırakılması gerekebilir.
4. Cihaz Algılama ve Uyarlanabilir Yönlendirme
Modern web uygulamalarının duyarlı olması ve farklı ekran boyutlarına ve cihaz yeteneklerine uyum sağlaması gerekir. Middleware, kullanıcının cihaz türünü algılamak ve onları sitenizin optimize edilmiş sürümlerine yönlendirmek için kullanılabilir.
Örnek: Mobil Kullanıcıları Mobil Optimize Edilmiş Bir Alt Alana Yönlendirme
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { device } from 'detection'
export function middleware(request: NextRequest) {
const userAgent = request.headers.get('user-agent')
if (userAgent) {
const deviceType = device(userAgent)
if (deviceType.type === 'phone') {
const mobileUrl = new URL(request.url)
mobileUrl.hostname = 'm.example.com'
return NextResponse.redirect(mobileUrl)
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/'],
}
Bu örnek, kullanıcının cihaz türünü User-Agent
başlığına göre belirlemek için detection
kitaplığını kullanır. Kullanıcı bir cep telefonundaysa, m.example.com
alt alan adına yönlendirilir (burada sitenizin mobil optimize edilmiş bir sürümünün barındırıldığını varsayarak). detection
paketini yüklemeyi unutmayın: npm install detection
.
Küresel Hususlar: Cihaz algılama mantığınızın, cihaz kullanımındaki bölgesel farklılıkları hesaba kattığından emin olun. Örneğin, bazı gelişmekte olan ülkelerde özellikli telefonlar hala yaygındır. Daha sağlam bir çözüm için Kullanıcı-Aracı algılama ve duyarlı tasarım tekniklerinin bir kombinasyonunu kullanmayı düşünün.
5. İstek Başlığı Zenginleştirme
Middleware, uygulamanızın rotaları tarafından işlenmeden önce istek başlıklarına bilgi ekleyebilir. Bu, uygulama mantığınız tarafından kullanılabilecek özel meta veriler (kullanıcı rolleri, kimlik doğrulama durumu veya istek kimlikleri gibi) eklemek için kullanışlıdır.
Örnek: Bir İstek Kimliği Ekleme
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { v4 as uuidv4 } from 'uuid'
export function middleware(request: NextRequest) {
const requestId = uuidv4()
const response = NextResponse.next()
response.headers.set('x-request-id', requestId)
return response
}
export const config = {
matcher: ['/api/:path*'], // Yalnızca API rotalarına uygulayın
}
Bu middleware, uuid
kitaplığını kullanarak benzersiz bir istek kimliği oluşturur ve bunu x-request-id
başlığına ekler. Bu kimlik daha sonra günlüğe kaydetme, izleme ve hata ayıklama amaçları için kullanılabilir. uuid
paketini yüklemeyi unutmayın: npm install uuid
.
Küresel Hususlar: Özel başlıklar eklerken, başlık boyutu sınırlarına dikkat edin. Bu sınırların aşılması beklenmeyen hatalara yol açabilir. Ayrıca, başlıklarına eklenen hassas bilgilerin (özellikle uygulamanız bir ters vekil sunucu veya CDN'nin arkasındaysa) uygun şekilde korunduğundan emin olun.
6. Güvenlik Geliştirmeleri: Hız Sınırlama
Middleware, belirli bir zaman diliminde bir istemcinin yapabileceği istek sayısını sınırlayarak, kötü niyetli saldırılara karşı ilk savunma hattı olarak görev yapabilir.
Örnek: Basit bir Mağaza Kullanarak Temel Hız Sınırlama
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const requestCounts: { [ip: string]: number } = {}
const WINDOW_SIZE_MS = 60000; // 1 dakika
const MAX_REQUESTS_PER_WINDOW = 100;
export function middleware(request: NextRequest) {
const clientIP = request.ip || '127.0.0.1' // İstemci IP'sini alın, yerel test için varsayılan olarak localhost
if (!requestCounts[clientIP]) {
requestCounts[clientIP] = 0;
}
requestCounts[clientIP]++;
if (requestCounts[clientIP] > MAX_REQUESTS_PER_WINDOW) {
return new NextResponse(
JSON.stringify({ message: 'Çok fazla istek' }),
{
status: 429,
headers: { 'Content-Type': 'application/json' }
}
);
}
// Pencereden sonra sayacı sıfırla
setTimeout(() => {
requestCounts[clientIP]--;
if (requestCounts[clientIP] <= 0) {
delete requestCounts[clientIP];
}
}, WINDOW_SIZE_MS);
return NextResponse.next();
}
export const config = {
matcher: ['/api/:path*'], // Tüm API rotalarına uygula
}
Bu örnek, her IP adresinden gelen istek sayısını izlemek için basit bir bellek içi mağaza (requestCounts
) tutar. Bir istemci WINDOW_SIZE_MS
içinde MAX_REQUESTS_PER_WINDOW
'u aşarsa, middleware bir 429 Çok Fazla İstek
hatası döndürür. Önemli: Bu basitleştirilmiş bir örnektir ve ölçeklenmediği ve hizmet reddi saldırılarına karşı savunmasız olduğu için üretim ortamları için uygun değildir. Üretimde kullanım için, Redis veya özel bir hız sınırlama hizmeti gibi daha sağlam bir hız sınırlama çözümü kullanmayı düşünün.
Küresel Hususlar: Hız sınırlama stratejileri, uygulamanızın özel özelliklerine ve kullanıcılarınızın coğrafi dağılımına göre uyarlanmalıdır. Farklı bölgeler veya kullanıcı segmentleri için farklı hız limitleri kullanmayı düşünün.
Kenar Durumları ve Potansiyel Tuzaklar
Middleware güçlü bir araç olmakla birlikte, sınırlamalarının ve potansiyel tuzaklarının farkında olmak çok önemlidir:
- Performans Etkisi: Middleware, her isteğe ek yük getirir. Middleware'de hesaplama açısından pahalı işlemler yapmaktan kaçının, çünkü bu performansı önemli ölçüde etkileyebilir. Herhangi bir performans darboğazını belirlemek ve optimize etmek için middleware'inizi profilleyin.
- Karmaşıklık: Middleware'i aşırı kullanmak, uygulamanızın anlaşılmasını ve bakımını zorlaştırabilir. Middleware'i dikkatli kullanın ve her middleware fonksiyonunun açık ve iyi tanımlanmış bir amaca sahip olmasını sağlayın.
- Test Etme: HTTP isteklerini simüle etmeyi ve sonuçta ortaya çıkan yanıtları incelemeyi gerektirdiği için middleware'i test etmek zorlayıcı olabilir. Middleware fonksiyonlarınız için kapsamlı birim ve entegrasyon testleri yazmak için Jest ve Supertest gibi araçları kullanın.
- Çerez Yönetimi: Middleware'de çerez ayarlarken dikkatli olun, çünkü bu önbelleğe alma davranışını etkileyebilir. Çerez tabanlı önbelleğe almanın sonuçlarını anladığınızdan ve önbellek başlıklarınızı buna göre yapılandırdığınızdan emin olun.
- Ortam Değişkenleri: Middleware'inizde kullanılan tüm ortam değişkenlerinin farklı ortamlar (geliştirme, hazırlık, üretim) için doğru şekilde yapılandırıldığından emin olun. Ortam değişkenlerinizi yönetmek için Dotenv gibi bir araç kullanın.
- Kenar Fonksiyon Sınırları: Middleware'in, yürütme süresi, bellek kullanımı ve paketlenmiş kod boyutu ile ilgili sınırlamaları olan Kenar Fonksiyonları olarak çalıştığını unutmayın. Middleware fonksiyonlarınızı hafif ve verimli tutun.
Next.js Middleware Kullanımı İçin En İyi Uygulamalar
Next.js middleware'in faydalarını en üst düzeye çıkarmak ve olası sorunlardan kaçınmak için şu en iyi uygulamaları izleyin:
- Basit Tutun: Her middleware fonksiyonu, iyi tanımlanmış, tek bir sorumluluğa sahip olmalıdır. Birden çok görev gerçekleştiren aşırı karmaşık middleware fonksiyonları oluşturmaktan kaçının.
- Performans İçin Optimize Edin: Performans darboğazlarından kaçınmak için middleware'de yapılan işlem miktarını en aza indirin. Tekrarlanan hesaplamalara olan ihtiyacı azaltmak için önbelleğe alma stratejileri kullanın.
- Kapsamlı Test Edin: Middleware fonksiyonlarınızın beklendiği gibi davrandığından emin olmak için kapsamlı birim ve entegrasyon testleri yazın.
- Kodunuzu Belgeleyin: Bakım kolaylığını artırmak için her middleware fonksiyonunun amacını ve işlevselliğini açıkça belgeleyin.
- Uygulamanızı İzleyin: Middleware fonksiyonlarınızın performansını ve hata oranlarını izlemek için izleme araçlarını kullanın.
- Yürütme Sırasını Anlayın: Middleware fonksiyonlarının hangi sırada yürütüldüğünün farkında olun, çünkü bu davranışlarını etkileyebilir.
- Ortam Değişkenlerini Akıllıca Kullanın: Middleware fonksiyonlarınızı farklı ortamlar için yapılandırmak için ortam değişkenlerini kullanın.
Sonuç
Next.js middleware, istekleri değiştirmek ve uygulamanızın davranışını kenarda özelleştirmek için güçlü bir yol sunar. Bu kılavuzda tartışılan gelişmiş istek değiştirme desenlerini anlayarak, sağlam, performanslı ve küresel olarak farkında olan Next.js uygulamaları oluşturabilirsiniz. Kenar durumlarını ve potansiyel tuzakları dikkatlice değerlendirmeyi ve middleware fonksiyonlarınızın güvenilir ve bakımı kolay olmasını sağlamak için yukarıda özetlenen en iyi uygulamaları izlemeyi unutmayın. Olağanüstü kullanıcı deneyimleri yaratmak ve web uygulamalarınız için yeni olanakların kilidini açmak için middleware'in gücünü kucaklayın.